package com.example.demo.MyBlockingQueue;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sfx
 * Date: 2023-09-10
 * Time: 21:30
 */
public class MyBlockingQueue<E> implements BlockingQueue<E> {
    // 队列主体
    private E[] array;
    // 头指针
    private int head;
    // 尾指针
    private int tail;
    // 队列中元素的个数
    private int size;

    // 锁->保证线程安全问题
    private ReentrantLock lock = new ReentrantLock();
    // 如果队列为空,不能弹出元素了,那么就放入headWaits中
    private Condition headWaits = lock.newCondition();//配合poll一起使用
    // 如果队列满了,不能放入元素了,那么就放入tailWaits中
    private Condition tailWaits = lock.newCondition();//配合offer一起使用

    public MyBlockingQueue(int capacity) {
        // 初始化数组
        array = (E[]) new Object[capacity];
    }

    @Override
    public void offer(E e) throws InterruptedException {
        lock.lock();
        try {
            while (isFull()) {
                tailWaits.await();
            }
            array[tail] = e;
            if (++tail == array.length) {
                tail = 0;
            }
            size++;
            // 添加元素之后,原本空,现在不空了,要唤醒正在等待取出元素的线程
            headWaits.signal();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean offer(E e, long timeout) throws InterruptedException {
        long nanos = TimeUnit.MILLISECONDS.toNanos(timeout);
        lock.lock();
        try {
            while (isFull()) {
                if (nanos <= 0) {
                    return false;
                }
                nanos = tailWaits.awaitNanos(nanos);
            }
            array[tail] = e;
            if (++tail == array.length) {
                tail = 0;
            }
            size++;
            // 添加元素之后,原本空,现在不空了,要唤醒正在等待取出元素的线程
            headWaits.signal();
        } finally {
            lock.unlock();
        }
        return true;
    }

    @Override
    public E poll() throws InterruptedException {
        lock.lock();
        E e;
        try {
            while (isEmpty()) {
                headWaits.await();
            }
            e = array[head];
            array[head] = null;
            if (++head == array.length) {
                head = 0;
            }
            size--;
            // 添加元素之后,原本空,现在不空了,要唤醒正在等待取出元素的线程
            tailWaits.signal();
        } finally {
            lock.unlock();
        }
        return e;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean isFull() {
        return size == array.length;
    }

    @Override
    public String toString() {
        return "MyBlockingQueue{" +
                "queue=" + Arrays.toString(array);
    }
}